package com.pz.cloud.framework.workflow.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pz.cloud.framework.base.dao.CommonDao;
import com.pz.cloud.framework.business.workflow.entity.ProcessBind;
import com.pz.cloud.framework.business.workflow.entity.ProcessInfo;
import com.pz.cloud.framework.business.workflow.entity.WaitDone;
import com.pz.cloud.framework.business.workflow.entity.WaitDoneUser;
import com.pz.cloud.framework.business.workflow.model.ProcessRecordModel;
import com.pz.cloud.framework.business.workflow.model.TaskNodeModel;
import com.pz.cloud.framework.business.workflow.service.*;
import com.pz.cloud.framework.model.AbstractSqlBuilder;
import com.pz.cloud.framework.model.SqlBuilder;
import com.pz.cloud.framework.util.BizUtil;
import com.pz.cloud.framework.workflow.mapper.WaitDoneMapper;
import com.pz.cloud.framework.workflow.mapper.WaitDoneUserMapper;
import org.apache.commons.lang.StringUtils;
import org.jeecg.modules.system.entity.SysPosition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 工作流服务
 * @author mazezhan
 */
@Transactional(rollbackFor = Exception.class)
@Service
//@DS("slave")
public class WaitDoneServiceImpl extends ServiceImpl<WaitDoneMapper,WaitDone> implements IWaitDoneService {
    @Autowired
    private WaitDoneMapper waitDoneMapper;
    @Autowired
    private IWaitDoneUserService waitDoneUserService;
    @Autowired
    private CommonDao commonDao;
    @Autowired
    private IProcessInfoService processInfoService;
    @Autowired
    private WaitDoneUserMapper waitDoneUserMapper;
    @Autowired
    private IWorkflowService workflowService;
    @Autowired
    private IWorkflowTaskService workflowTaskService;
    @Override
    public List<WaitDoneUser> getUserByWaitDoneId(String waitDoneId) {
        List<WaitDoneUser> waitDoneUsers = waitDoneMapper.getUserByWaitDoneId(waitDoneId);
        return waitDoneUsers;
    }

    @Override
    public List<WaitDoneUser> getCurUserByBizId(String bizId) {
        AbstractSqlBuilder sqlBuilder = SqlBuilder.init("select wu.* from ").appendTable(WaitDoneUser.class).append(" wu inner join ").appendTable(WaitDone.class)
                .append(" w on wu.wait_done_id = w.id where status = 0 and w.biz_id = :bizId").setParms("bizId", bizId)
                .returnType(WaitDoneUser.class);
        List list = commonDao.findList(sqlBuilder);
        return list;
    }

    @Override
    public IPage<WaitDone> findPage(WaitDone waitDone) {
        if(waitDone.getStatus()==null){
            waitDone.setStatus(0);
        }
        AbstractSqlBuilder sqlBuilder = SqlBuilder.init("select w.*,wu.wait_user_name,wu.wait_user_id,pi.title,pb.biz_url,")
                .append("(CASE WHEN w.due_date IS NULL THEN 0 ELSE (CASE WHEN TIMESTAMPDIFF(SECOND,w.due_date,IFNULL(w.deal_time, NOW()))>0 THEN 1 ELSE 0 END) END ) time_out_flag" )
                .from(waitDone.getTableName(),"w")
                .leftJoin(WaitDoneUser.class,"wu").on("w.id = wu.wait_done_id")
                .leftJoin(ProcessInfo.class,"pi").on("w.process_instance_id = pi.id")
                .leftJoin(ProcessBind.class,"pb").on("pi.process_bind_id = pb.id ")
                .page(waitDone)
                .joinCondition(waitDone, "w").returnType(WaitDone.class)
                .append(" and wu.wait_user_id = :userId").setParms("userId",BizUtil.getUserId())
                .orderBy(" w.create_time desc");
        if(StringUtils.isNotEmpty(waitDone.getWaitUserName())){
            sqlBuilder.append(" and wu.wait_user_name like :waitUserName");
            sqlBuilder.setParmsLike("waitUserName",waitDone.getWaitUserName());
        }
        if(StringUtils.isNotEmpty(waitDone.getWaitUserId())){
            sqlBuilder.append(" and wu.wait_user_id = :waitUserId");
            sqlBuilder.setParms("waitUserId",waitDone.getWaitUserId());
        }
        if(StringUtils.isNotEmpty(waitDone.getTitle())){
            sqlBuilder.append(" and pi.title like :title");
            sqlBuilder.setParmsLike("title",waitDone.getTitle());
        }
        IPage page = commonDao.findPage(sqlBuilder);

        /**
         * 标记能否
         */
//        List<WaitDone> data = page.getRecords();
//        if(!CollectionUtils.isEmpty(data)){
//            for (WaitDone d : data) {
//                String processInstanceId = d.getProcessInstanceId();
//                ProcessInfo processInfo = processInfoService.getById(processInstanceId);
//                if(processInfo!=null&&processInfo.getCreatorId().equals(d.getWaitUserId())){
//                    d.setCancel(1);
//                }else{
//                    d.setCancel(0);
//                }
//            }
//        }
        return page;
    }
    @Override
    public IPage<WaitDone> findHasDonePage(WaitDone waitDone) {
        if(StringUtils.isEmpty(waitDone.getDealUserId())){
            waitDone.setDealUserId(BizUtil.getUserId());
        }
        AbstractSqlBuilder sqlBuilder = SqlBuilder.init("select w.*,pi.title,pb.biz_url from ").append(waitDone.getTableName()).append(" w ")
                .append(" left join ").append(BizUtil.getTableName(ProcessInfo.class)).append(" pi on w.process_instance_id = pi.id ")
                .append(" left join ").append(BizUtil.getTableName(ProcessBind.class)).append(" pb on pi.process_bind_id = pb.id ")
                .page(waitDone)
                .joinCondition(waitDone, "w").returnType(WaitDone.class)
                .orderBy(" w.create_time desc");
        IPage page = commonDao.findPage(sqlBuilder);

        /**
         * 标记能否撤回
         */
        List<WaitDone> data = page.getRecords();
        if(!CollectionUtils.isEmpty(data)){
            for (WaitDone d : data) {
                boolean withdrawTask = workflowTaskService.isWithdrawTask(d.getId());
                if(withdrawTask){
                    d.setWithdrawFlag(1);
                }else{
                    d.setWithdrawFlag(0);
                }
            }
        }
        return page;
    }

    @Override
    public boolean updateStatusByBizId(String bizId, Integer status) {
       String updateSql = "update oa_wait_done set status = :status where biz_id = :bizId";
        Map<String,Object> parms = new HashMap<>();
        parms.put("status",status);
        parms.put("bizId",bizId);
        return commonDao.execute(updateSql,parms);
    }

    @Override
    public List<WaitDone> findList(WaitDone waitDone) {
        waitDone.setPaging(false);
        IPage<WaitDone> page = findPage(waitDone);
        return page.getRecords();
    }
    @Override
    public List<WaitDone> findByTaskKeyAndProcInstanceId(String taskKey,String processInstanceId) {
        AbstractSqlBuilder sqlBuilder = SqlBuilder.init("select w.*,wu.wait_user_name  from ").append(BizUtil.getTableName(WaitDone.class)).append(" w left join ")
                .append(BizUtil.getTableName(WaitDoneUser.class))
                .append(" wu on w.id = wu.wait_done_id ")
                .append(" inner join ").append(" act_hi_actinst aha on w.id = aha.task_id_ ")
                .append(" where aha.act_id_ = :taskKey and w.process_instance_id = :processInstanceId")
                .orderBy(" w.create_time desc").returnType(WaitDone.class);
        sqlBuilder.setParms("taskKey",taskKey);
        sqlBuilder.setParms("processInstanceId",processInstanceId);
        List<WaitDone> list = commonDao.findList(sqlBuilder);
        return list;
    }
    @Override
    public IPage<ProcessRecordModel> findByProcInstanceId(String processInstanceId) {
        AbstractSqlBuilder sqlBuilder = SqlBuilder.init("select w.* from ").append(BizUtil.getTableName(WaitDone.class)).append(" w  ")
                .append(" where  w.process_instance_id = :processInstanceId").setParms("processInstanceId",processInstanceId)
                .orderBy(" w.create_time asc").returnType(ProcessRecordModel.class);
        IPage page = commonDao.findPage(sqlBuilder);
        return page;
    }
    @Override
    public IPage<ProcessRecordModel> findByBizId(String bizId) {
        AbstractSqlBuilder sqlBuilder = SqlBuilder.init("select w.* from ").append(BizUtil.getTableName(WaitDone.class)).append(" w  ")
                .append(" where  w.biz_id = :bizId").setParms("bizId",bizId)
                .orderBy(" w.create_time asc").returnType(ProcessRecordModel.class);
        IPage page = commonDao.findPage(sqlBuilder);
        return page;
    }

    /**
     * 查询所有审批节点最新的记录
     * @param bizId
     * @return
     */
    @Override
    public List<ProcessRecordModel> findSignleRecordByBizId(String bizId) {
        IPage<ProcessRecordModel> records = findByBizId(bizId);
        List<ProcessRecordModel> list = records.getRecords();
        List<ProcessRecordModel> result = null;
        if(!CollectionUtils.isEmpty(list)){
            String firstTaskName = list.get(0).getTaskName();
            Map<String,ProcessRecordModel> taskMap = new LinkedHashMap<>();
            List<ProcessRecordModel> filterList = list.stream().filter(p -> p.getDealTime() != null && !p.getTaskName().equals(firstTaskName))
                    .collect(Collectors.toList());

            for (ProcessRecordModel model : filterList) {
                taskMap.put(model.getTaskName(),model);
            }

            result = taskMap.values().stream().collect(Collectors.toList());
        }
        return result;
    }
    @Override
    public List<WaitDone> findByParentId(String parentId) {
        LambdaQueryWrapper<WaitDone> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WaitDone::getParentId,parentId);
        return list(queryWrapper);
    }

    @Override
    public void deleteWaitDone(WaitDone waitDone) {
        this.removeById(waitDone.getId());
        LambdaQueryWrapper<WaitDoneUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WaitDoneUser::getWaitDoneId,waitDone.getId());
        int delete = waitDoneUserMapper.delete(queryWrapper);
    }

    @Override
    public void deleteProcess(String id) {
        WaitDone waitDone = getById(id);
        if(waitDone!=null){
            waitDone.setStatus(1);
            waitDone.setResult("流程删除");
            waitDone.setDealUserName(BizUtil.getUser().getRealname());
            waitDone.setDealTime(new Date());
            waitDone.setDealUserId(BizUtil.getUserId());
            workflowService.deleteProcessByBizId(waitDone.getBizId(),false);
        }
    }


    @Override
    public void deleteByBizId(String bizId) {
        LambdaQueryWrapper<WaitDone> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(WaitDone::getBizId,bizId);

        List<WaitDone> list = list(queryWrapper);
        if(!CollectionUtils.isEmpty(list)){
            for (WaitDone waitDone : list) {
                waitDoneUserService.deleteByWaitDoneId(waitDone.getId());
            }
        }
        remove(queryWrapper);
    }
}
